package chat;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server {


    /*运行在服务端的ServerSocket主要负责:
    1:向系统申请服务端口
    客户端就是通过这个端口与之连接的
    2:监听申请的服务端口，当一个客户端通过
    该端口尝试建立连接时,ServerSocket
    会在服务端创建一个Socket与客户端建立
    连接*/

    private ServerSocket serverSocket;

    //保存所以客户端的输出流
    private List<PrintWriter> list;

    public Server() throws IOException {

        serverSocket=new ServerSocket(8088);

        list=new ArrayList<PrintWriter>();

    }


    public synchronized void addOut(PrintWriter printWriter){
        list.add(printWriter);
    }


    //将给定的输出流从共享集合中移除
    public synchronized void removeOut(PrintWriter printWriter){
        list.remove(printWriter);
    }


    //将消息发送给客户端
    public synchronized void sendMessage(String string){
        for (PrintWriter printWriter:list) {
            printWriter.println(string);
        }
    }

    public void start(){
        try {
            while (true) {
               /* ServerSocket的accept方法
                是一个阻塞方法,作用是监听
                服务端口,直到一个客户端连接
                并创建一个Socket ,使用该Socket
                即可与刚连接的客户端进行交互|*/
                System.out.println("等待客户端连接....");
                Socket socke=serverSocket.accept();
                System.out.println("一个客户端连接了....");
                //启动一个线程完成客户端的交换

                ClientHandler clientHandler=new ClientHandler(socke);
                Thread thread=new Thread(clientHandler);
                thread.start();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try {
            Server server=new Server();
            server.start();
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    //该线程负责与客户端交互
    class ClientHandler implements Runnable{

        private Socket socket;

        private String host;

        private String nikeName;

        public ClientHandler(Socket socket){
            this.socket=socket;

            //通过socket可以获取远端计算机的地址信息
            InetAddress address=socket.getInetAddress();
            //获取ip
            host=address.getHostAddress();
        }

        @Override
        public void run() {
            PrintWriter printWriter = null;
            try {
            /* Socket提供的方法
            InputStream
            getInputStream( )
            该方法可以获取一个输入流，从该流读取的
            数据就是从远端计算机发送过来的*/

                InputStream inputStream=socket.getInputStream();

                InputStreamReader inputStreamReader=new InputStreamReader(inputStream,"UTF-8");

                BufferedReader bufferedReader=new BufferedReader(inputStreamReader);

                //首先读取第一行作为昵称
                nikeName=bufferedReader.readLine();

                sendMessage(nikeName+":上线了");

                //把接收到的消息发送给客户端
                OutputStream outputStream=socket.getOutputStream();

                OutputStreamWriter outputStreamWriter=new OutputStreamWriter(outputStream,"UTF-8");

                printWriter=new PrintWriter(outputStreamWriter,true);


                //将客户端的输出流存到共享集合
                addOut(printWriter);



                //用while true
                // 当windows 的客户端断开连接的时候这里会出现抛出异常  java.net.SocketException: Connection reset
                // 用Linux的时候 这里就会一直读到null 所以改成
                String message=null;
                while ((message=bufferedReader.readLine())!=null){
//                    System.out.println(host+"说:"+message);
//                    printWriter.println(host+"说:"+message);
                    sendMessage(nikeName+"说:"+message);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                //处理客户端断开后的逻辑
                removeOut(printWriter);
                sendMessage(nikeName+"下线了");
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


}



